﻿#include "stdafx.h"
#include "redisCli.h"
#include "redisReply.h"
#include <string>

#ifndef _STATIC
CMD_INFO Cmd_redisCli_construct =
{
	/*ccname*/	_WT(""),
	/*egname*/	_WT(""),
	/*explain*/	_WT(""),
	/*category*/-1,
	/*state*/	CT_IS_OBJ_CONSTURCT_CMD | CT_IS_HIDED,
	/*ret*/		_SDT_NULL,
	/*reserved*/0,
	/*level*/	LVL_SIMPLE,
	/*bmp inx*/	0,
	/*bmp num*/	0,
	/*ArgCount*/0,
	/*arg lp*/	NULL,
};
CMD_INFO Cmd_redisCli_destruct =
{
	/*ccname*/	_WT(""),
	/*egname*/	_WT(""),
	/*explain*/	_WT(""),
	/*category*/-1,
	/*state*/	CT_IS_OBJ_FREE_CMD | CT_IS_HIDED,
	/*ret*/		_SDT_NULL,
	/*reserved*/0,
	/*level*/	LVL_SIMPLE,
	/*bmp inx*/	0,
	/*bmp num*/	0,
	/*ArgCount*/0,
	/*arg lp*/	NULL,
};
static ARG_INFO Arg_Copy =
{
	/*name*/	_WT("rhs"),
	/*explain*/	_WT(""),
	/*bmp inx*/	0,
	/*bmp num*/	0,
	/*type*/	DTP_REDIS_CONTEXT,
	/*default*/	0,
	/*state*/	NULL
};
CMD_INFO Cmd_redisCli_copy =
{
	/*ccname*/	_WT(""),
	/*egname*/	_WT(""),
	/*explain*/	_WT(""),
	/*category*/-1,
	/*state*/	CT_IS_OBJ_COPY_CMD | CT_IS_HIDED,
	/*ret*/		_SDT_NULL,
	/*reserved*/0,
	/*level*/	LVL_SIMPLE,
	/*bmp inx*/	0,
	/*bmp num*/	0,
	/*ArgCount*/1,
	/*arg lp*/	&Arg_Copy,
};
#endif
EXTERN_C
void redis_redisCli_construct(PMDATA_INF pRetData, INT nArgCount, PMDATA_INF pArgInf)
{
	*pArgInf->m_ppCompoundData = NULL;
}

EXTERN_C
void redis_redisCli_destruct(PMDATA_INF pRetData, INT nArgCount, PMDATA_INF pArgInf)
{
	redisContext* redis = (redisContext*)*pArgInf->m_ppCompoundData;
	if (redis) redisFree(redis);
	*pArgInf->m_ppCompoundData = NULL;
}

EXTERN_C
void redis_redisCli_copy(PMDATA_INF pRetData, INT nArgCount, PMDATA_INF pArgInf)
{
	//不支持copy操作啊.亲.
	//交换俩边的对象.
	redisContext* redis1 = (redisContext*)*pArgInf[0].m_ppCompoundData;
	redisContext* redis2 = (redisContext*)*pArgInf[1].m_ppCompoundData;
	*pArgInf[0].m_ppCompoundData = redis2;
	*pArgInf[1].m_ppCompoundData = redis1;
}

#ifndef _STATIC
static ARG_INFO Arg_Connect[] =
{
	{
		/*name*/	_WT("服务地址"),
		/*explain*/	_WT("redis服务器ip地址."),
		/*bmp inx*/	0,
		/*bmp num*/	0,
		/*type*/	SDT_TEXT,
		/*default*/	0,
		/*state*/	NULL,
	},
	{
		/*name*/	_WT("端口"),
		/*explain*/	_WT("redis服务器端口."),
		/*bmp inx*/	0,
		/*bmp num*/	0,
		/*type*/	SDT_INT,
		/*default*/	0,
		/*state*/	NULL,
	},
	{
		/*name*/	_WT("超时时间"),
		/*explain*/	_WT("指定连接redis服务器的超时时间.单位毫秒."),
		/*bmp inx*/	0,
		/*bmp num*/	0,
		/*type*/	SDT_INT,
		/*default*/	0,
		/*state*/	NULL,
	},
};
CMD_INFO Cmd_redisCli_connect =
{
	/*ccname*/	_WT("连接Redis"),
	/*egname*/	_WT("ConnectRedis"),
	/*explain*/	_WT("连接redis服务器.成功返回真.失败可通过最后错误取得错误文字说明."),
	/*category*/-1,
	/*state*/	_CMD_OS(OS_ALL),
	/*ret*/		SDT_BOOL,
	/*reserved*/0,
	/*level*/	LVL_SIMPLE,
	/*bmp inx*/	0,
	/*bmp num*/	0,
	/*ArgCount*/sizeArray(Arg_Connect),
	/*arg lp*/	Arg_Connect,
};
#endif
/*连接Redis
@ip				文本型,
@port			整数型,
@timeout		整数型,
@return			逻辑型,
*/
EXTERN_C
void redis_redisCli_connect(PMDATA_INF pRetData, INT nArgCount, PMDATA_INF pArgInf)
{
	const char* serverIp = pArgInf[1].m_pText;
	unsigned int port = pArgInf[2].m_uint;
	int timeout = pArgInf[3].m_int;

	struct timeval tv;
	tv.tv_sec = timeout / 1000;
	tv.tv_usec = timeout % 1000 * 1000;

	BOOL result = FALSE;
	redisContext* context = redisConnectWithTimeout(serverIp, port, tv);
	if (context) {
		result = context->err == REDIS_OK ? TRUE : FALSE;
		if (result) *pArgInf->m_ppCompoundData = context;
		else redisFree(context);
	}
	pRetData->m_bool = result;
}
#ifndef _STATIC
CMD_INFO Cmd_redisCli_disconnect =
{
	/*ccname*/	_WT("释放连接"),
	/*egname*/	_WT("redisFree"),
	/*explain*/	_WT("断开与redis服务器的连接."),
	/*category*/-1,
	/*state*/	_CMD_OS(OS_ALL),
	/*ret*/		_SDT_NULL,
	/*reserved*/0,
	/*level*/	LVL_SIMPLE,
	/*bmp inx*/	0,
	/*bmp num*/	0,
	/*ArgCount*/0,
	/*arg lp*/	NULL,
};
#endif
/*断开连接
*/
EXTERN_C
void redis_redisCli_disconnect(PMDATA_INF pRetData, INT nArgCount, PMDATA_INF pArgInf)
{
	redisContext* redis = (redisContext*)*pArgInf->m_ppCompoundData;
	if (redis) redisFree(redis);
	*pArgInf->m_ppCompoundData = NULL;
}
#ifndef _STATIC
CMD_INFO Cmd_redisCli_isconnect =
{
	/*ccname*/	_WT("是否连接"),
	/*egname*/	_WT("isConnect"),
	/*explain*/	_WT("是否与redis服务器建立连接."),
	/*category*/-1,
	/*state*/	_CMD_OS(OS_ALL),
	/*ret*/		SDT_BOOL,
	/*reserved*/0,
	/*level*/	LVL_SIMPLE,
	/*bmp inx*/	0,
	/*bmp num*/	0,
	/*ArgCount*/0,
	/*arg lp*/	NULL,
};
#endif
EXTERN_C
void redis_redisCli_isconnect(PMDATA_INF pRetData, INT nArgCount, PMDATA_INF pArgInf)
{
	BOOL result = FALSE;
	redisContext* context = (redisContext*)*pArgInf->m_ppCompoundData;
	if (context) {
		redisReply* reply = (redisReply*)redisCommand(context, "echo OK");
		if (reply && reply->type == REDIS_REPLY_STRING) {
			if (!strcmp(reply->str, "OK"))
				result = TRUE;
			//把错误字符串拷贝过去.
			memcpy(context->errstr, reply->str, reply->len);
			context->errstr[reply->len] = 0;
			freeReplyObject(reply);
		}
	}
	pRetData->m_bool = result;
}

#ifndef _STATIC
static ARG_INFO Arg_auth[] =
{
	{
		/*name*/	_WT("密码"),
		/*explain*/	_WT("redis授权密码."),
		/*bmp inx*/	0,
		/*bmp num*/	0,
		/*type*/	SDT_TEXT,
		/*default*/	0,
		/*state*/	NULL,
	},
};
CMD_INFO Cmd_redisCli_auth =
{
	/*ccname*/	_WT("验证权限"),
	/*egname*/	_WT("auth"),
	/*explain*/	_WT("redis权限认证,成功返回真."),
	/*category*/-1,
	/*state*/	_CMD_OS(OS_ALL),
	/*ret*/		SDT_BOOL,
	/*reserved*/0,
	/*level*/	LVL_SIMPLE,
	/*bmp inx*/	0,
	/*bmp num*/	0,
	/*ArgCount*/sizeArray(Arg_auth),
	/*arg lp*/	Arg_auth,
};
#endif
EXTERN_C
void redis_redisCli_auth(PMDATA_INF pRetData, INT nArgCount, PMDATA_INF pArgInf)
{
	BOOL result = FALSE;
	redisContext* context = (redisContext*)*pArgInf->m_ppCompoundData;
	if (context) {
		const char* password = pArgInf[1].m_pText;
		redisReply* pReply = (redisReply*)redisCommand(context, "auth %s", password);
		if (pReply && pReply->type == REDIS_REPLY_STATUS) {
#ifdef _MSC_VER
			if (!_stricmp(pReply->str, "OK"))
#else
			if (!strcmp(pReply->str, "OK"))
#endif
				result = TRUE;
		}
		if (pReply) {
			//把错误字符串拷贝过去.
			memcpy(context->errstr, pReply->str, pReply->len);
			context->errstr[pReply->len] = 0;
			freeReplyObject(pReply);
			pReply = NULL;
		}
	}
	pRetData->m_bool = result;
}
#ifndef _STATIC
static ARG_INFO Arg_Command[] =
{
	{
		/*name*/	_WT("命令文本"),
		/*explain*/	_WT("redis命令,该命令支持格式化.参考sprintf"),
		/*bmp inx*/	0,
		/*bmp num*/	0,
		/*type*/	SDT_TEXT,
		/*default*/	0,
		/*state*/	NULL,
	},
	{
		/*name*/	_WT("参数"),
		/*explain*/	_WT("指定用于格式化的参数."),
		/*bmp inx*/	0,
		/*bmp num*/	0,
		/*type*/	_SDT_ALL,
		/*default*/	0,
		/*state*/	AS_RECEIVE_VAR_OR_OTHER | AS_DEFAULT_VALUE_IS_EMPTY,
	},
};
CMD_INFO Cmd_redisCli_runcommand =
{
	/*ccname*/	_WT("执行命令"),
	/*egname*/	_WT("runCommand"),
	/*explain*/	_WT("向redis发送命令,返回命令执行结果."),
	/*category*/-1,
	/*state*/	_CMD_OS(OS_ALL) | CT_ALLOW_APPEND_NEW_ARG,
	/*ret*/		DTP_REDIS_REPLY,
	/*reserved*/0,
	/*level*/	LVL_HIGH,
	/*bmp inx*/	0,
	/*bmp num*/	0,
	/*ArgCount*/sizeArray(Arg_Command),
	/*arg lp*/	Arg_Command,
};
#endif
EXTERN_C
void redis_redisCli_runcommand(PMDATA_INF pRetData, INT nArgCount, PMDATA_INF pArgInf)
{
	redisContext* context = (redisContext*)*pArgInf->m_ppCompoundData;
	if (!context) {
		pRetData->m_pCompoundData = MMalloc(4);
		*pRetData->m_ppCompoundData = NULL;
		return;
	}
	++pArgInf;
	const char* format = pArgInf[0].m_pText;
	char argv[512];
	char* pArgv = argv;

	for (INT i = 1; i < nArgCount; ++i) {
		++pArgInf;
		if (pArgInf->m_dtDataType != _SDT_NULL) {
			switch (pArgInf->m_dtDataType) {
			case SDT_BYTE:
				*(INT*)pArgv = 0;
				*(BYTE*)pArgv = pArgInf->m_byte;
				pArgv += sizeof(INT);
				break;
			case SDT_SHORT:
				*(INT*)pArgv = 0;
				*(SHORT*)pArgv = pArgInf->m_short;
				pArgv += sizeof(INT);
				break;
			case SDT_INT:
				*(INT*)pArgv = pArgInf->m_int;
				pArgv += sizeof(INT);
				break;
			case SDT_TEXT:
				*(char**)pArgv = pArgInf->m_pText;
				pArgv += sizeof(char*);
				break;
			case SDT_BIN:
				do
				{
					int count;
					LPBYTE ary = GetAryElementInf(pArgInf->m_pAryData, &count);
					*(char**)pArgv = (char*)ary;
				} while (false);
				pArgv += sizeof(char*);
				break;
			case SDT_INT64:
				*(INT64*)pArgv = pArgInf->m_int64;
				pArgv += sizeof(INT64);
				break;
			case SDT_FLOAT:
				*(double*)pArgv = pArgInf->m_float;
				pArgv += sizeof(double);
				break;
			case SDT_DATE_TIME:
			case SDT_DOUBLE:
				*(double*)pArgv = pArgInf->m_double;
				pArgv += sizeof(double);
				break;
			case SDT_BOOL:
				*(INT*)pArgv = pArgInf->m_bool;
				pArgv += sizeof(INT);
				break;
			default:
				if (pArgInf->m_dtDataType&DT_IS_VAR) {
					DATA_TYPE dtType = pArgInf->m_dtDataType & ~DT_IS_VAR;
					switch (dtType) {
					case SDT_BYTE:
						*(INT*)pArgv = 0;
						*(BYTE*)pArgv = *pArgInf->m_pByte;
						pArgv += sizeof(INT);
						break;
					case SDT_SHORT:
						*(INT*)pArgv = 0;
						*(SHORT*)pArgv = *pArgInf->m_pShort;
						pArgv += sizeof(INT);
						break;
					case SDT_INT:
						*(INT*)pArgv = *pArgInf->m_pInt;
						pArgv += sizeof(INT);
						break;
					case SDT_TEXT:
						*(char**)pArgv = *pArgInf->m_ppText;
						pArgv += sizeof(char*);
						break;
					case SDT_BIN:
						do
						{
							int count;
							LPBYTE ary = GetAryElementInf(*pArgInf->m_ppAryData, &count);
							*(char**)pArgv = (char*)ary;
						} while (false);
						pArgv += sizeof(char*);
						break;
					case SDT_INT64:
						*(INT64*)pArgv = *pArgInf->m_pInt64;
						pArgv += sizeof(INT64);
						break;
					case SDT_FLOAT:
						*(double*)pArgv = *pArgInf->m_pFloat;
						pArgv += sizeof(double);
						break;
					case SDT_DATE_TIME:
					case SDT_DOUBLE:
						*(double*)pArgv = *pArgInf->m_pDouble;
						pArgv += sizeof(double);
						break;
					case SDT_BOOL:
						*(INT*)pArgv = *pArgInf->m_pBool;
						pArgv += sizeof(INT);
						break;
					}
				}
				break;
			}
		}
	}
	void* result = NULL;
	if (pArgv != argv) {
		va_list ap = (va_list)argv;
		result = redisvCommand(context, format, ap);
	}
	else {
		result = redisCommand(context, format);
	}
	pRetData->m_pCompoundData = MMalloc(sizeof(void*));
	OBJECT_INFO* pInfo = (OBJECT_INFO*)MMalloc(sizeof(OBJECT_INFO));
	if (pInfo) {
		pInfo->child = FALSE;
		pInfo->reply = (redisReply*)result;
	}
	*pRetData->m_ppCompoundData = pInfo;
}
#ifndef _STATIC
CMD_INFO Cmd_redisCli_lasterrno =
{
	/*ccname*/	_WT("取错误码"),
	/*egname*/	_WT("LastError"),
	/*explain*/	_WT("获取最后一次操作redis时产生的错误码.参考#REDIS_ERR开头的常量."),
	/*category*/-1,
	/*state*/	_CMD_OS(OS_ALL),
	/*ret*/		SDT_INT,
	/*reserved*/0,
	/*level*/	LVL_SIMPLE,
	/*bmp inx*/	0,
	/*bmp num*/	0,
	/*ArgCount*/0,
	/*arg lp*/	NULL,
};
#endif
EXTERN_C
void redis_redisCli_lasterrno(PMDATA_INF pRetData, INT nArgCount, PMDATA_INF pArgInf)
{
	pRetData->m_int = -1;
	redisContext* context = (redisContext*)*pArgInf->m_ppCompoundData;
	if (context) pRetData->m_int = context->err;
}
#ifndef _STATIC
CMD_INFO Cmd_redisCli_lasterror =
{
	/*ccname*/	_WT("取错误消息"),
	/*egname*/	_WT("lastErrMsg"),
	/*explain*/	_WT("获取最后一次操作redis时产生的错误消息."),
	/*category*/-1,
	/*state*/	_CMD_OS(OS_ALL),
	/*ret*/		SDT_TEXT,
	/*reserved*/0,
	/*level*/	LVL_SIMPLE,
	/*bmp inx*/	0,
	/*bmp num*/	0,
	/*ArgCount*/0,
	/*arg lp*/	NULL,
};
#endif
EXTERN_C
void redis_redisCli_lasterror(PMDATA_INF pRetData, INT nArgCount, PMDATA_INF pArgInf)
{
	redisContext* context = (redisContext*)*pArgInf->m_ppCompoundData;
	if (context) {
		pRetData->m_pText = CloneTextData(context->errstr);
	}else{
		pRetData->m_pText = CloneTextData("未连接");
	}
}
